package org.rsbot.script.methods;

import org.rsbot.script.wrappers.RSComponent;

import java.util.ArrayList;
import java.util.List;

/**
 * Clan chat related operations.
 *
 * @author Debauchery
 * @author Hyperion
 */
public class ClanChat extends MethodProvider {
    public static final int INTERFACE_CLAN_CHAT = 1110;
    public static final int INTERFACE_CLAN_CHAT_CHECK = 55;
    public static final int INTERFACE_CLAN_CHAT_USERS_LIST = 9;
    public static final int INTERFACE_CLAN_CHAT_INFO_BUTTON = 0;
    public static final int INTERFACE_CLAN_CHAT_SETTINGS_BUTTON = 0;
    public static final int INTERFACE_CLAN_CHAT_INFO = 1107;
    public static final int INTERFACE_CLAN_CHAT_INFO_CHANNEL_NAME = 172;
    public static final int INTERFACE_CLAN_CHAT_INFO_CHANNEL_OWNER = 35;
    public static final int INTERFACE_CLAN_CHAT_INFO_CLOSE_BUTTON = 174;
    public static final int INTERFACE_CLAN_CHAT_SETTINGS = 1096;
    public static final int INTERFACE_CLAN_CHAT_SETTINGS_LEAVE = 281;
    public static final int INTERFACE_CLAN_CHAT_SETTINGS_CLOSE_BUTTON = 341;

    ClanChat(final MethodContext ctx) {
        super(ctx);
    }

    /**
     * Gets the owner of the channel.
     *
     * @return The owner of the channel or null if unavailable
     */
    public String getOwner() {
        String owner = null;
        if (isInformationOpen() || openInformation()) {
            owner = methods.interfaces.getComponent(INTERFACE_CLAN_CHAT_INFO, INTERFACE_CLAN_CHAT_INFO_CHANNEL_OWNER).getText();
        }
        return owner != null ? owner.trim() : null;
    }

    /**
     * Gets the name of the channel.
     *
     * @return The name of the channel or null if none
     */
    public String getChannelName() {
        String channelName = null;
        if (isInformationOpen() || openInformation()) {
            channelName = methods.interfaces.getComponent(INTERFACE_CLAN_CHAT_INFO, INTERFACE_CLAN_CHAT_INFO_CHANNEL_NAME).getText();
        }
        return channelName != null ? channelName.trim() : null;
    }

    /**
     * Gets the users in the channel.
     *
     * @return The users in the channel or null if unavailable
     */
    public FriendChat.User[] getUsers() {
        if (inChannel()) {
            RSComponent c = methods.interfaces.getComponent(INTERFACE_CLAN_CHAT, INTERFACE_CLAN_CHAT_USERS_LIST);
            if (c.isValid()) {
                List<FriendChat.User> mates = new ArrayList<FriendChat.User>();
                for (final RSComponent user : c.getComponents()) {
                    if (user == null || user.getComponentName().isEmpty()) {
                        continue;
                    }
                    final String name = user.getComponentName();
                    final int userIndex = user.getComponentIndex();
                    final RSComponent rank = methods.interfaces.getComponent(INTERFACE_CLAN_CHAT, 10).getComponent(userIndex);
                    final RSComponent world = methods.interfaces.getComponent(INTERFACE_CLAN_CHAT, 11).getComponent(userIndex);
                    mates.add(new FriendChat.User(name, rank, world));
                }
                return mates.toArray(new FriendChat.User[mates.size()]);
            }
        }
        return new FriendChat.User[0];
    }

    /**
     * Gets the first clanmate matching with any of the provided names.
     *
     * @param names the names to look for
     * @return an instance of <code>ClanUser</code> or <code>null</code> if no results
     */
    public FriendChat.User getUser(final String... names) {
        final FriendChat.User[] clanMates = getUsers();
        for (final String name : names) {
            for (final FriendChat.User clanMate : clanMates) {
                if (name.equalsIgnoreCase(clanMate.getName())) {
                    return clanMate;
                }
            }
        }
        return null;
    }


    /**
     * Returns whether or not we're in a channel.
     *
     * @return <tt>true</tt> if in a channel; otherwise <tt>false</tt>
     */
    public boolean inChannel() {
        if (methods.game.getTab() != Game.Tab.CLAN_CHAT)
            methods.game.openTab(Game.Tab.CLAN_CHAT);
        return methods.game.getTab() == Game.Tab.CLAN_CHAT && methods.interfaces.getComponent(INTERFACE_CLAN_CHAT, INTERFACE_CLAN_CHAT_CHECK).containsText("If you");
    }

    /**
     * Opens clan information interface.
     *
     * @return <tt>true</tt> if open/has been opened; otherwise <tt>false</tt>
     */
    public boolean openInformation() {
        if (!isInformationOpen() && inChannel()) {
            if (methods.interfaces.getComponent(INTERFACE_CLAN_CHAT_INFO, INTERFACE_CLAN_CHAT_INFO_BUTTON).doClick())
                for (byte i = 0; i < 10 && !isInformationOpen(); i++) {
                    sleep(random(80, 121));
                }
        }
        return isInformationOpen();
    }

    /**
     * Closes clan information interface.
     *
     * @return <tt>true</tt> if closed/has been closed; otherwise <tt>false</tt>
     */
    public boolean closeInformation() {
        if (isInformationOpen()) {
            if (methods.interfaces.getComponent(INTERFACE_CLAN_CHAT_INFO, INTERFACE_CLAN_CHAT_INFO_CLOSE_BUTTON).doClick())
                for (byte i = 0; i < 10 && isInformationOpen(); i++) {
                    sleep(random(80, 121));
                }
        }
        return !isInformationOpen();
    }

    /**
     * Checks to see if the information interface is open/valid.
     *
     * @return <tt>true</tt> if open; otherwise <tt>false</tt>
     */
    public boolean isInformationOpen() {
        return methods.interfaces.get(INTERFACE_CLAN_CHAT_INFO).isValid();
    }

    /**
     * Opens clan Settings interface.
     *
     * @return <tt>true</tt> if open/has been opened; otherwise <tt>false</tt>
     */
    public boolean openSettings() {
        if (!areSettingsOpen()  && inChannel()) {
            if (methods.interfaces.getComponent(INTERFACE_CLAN_CHAT_SETTINGS, INTERFACE_CLAN_CHAT_SETTINGS_BUTTON).doClick()) {
                for (byte i = 0; i < 10 && !areSettingsOpen(); i++) {
                    sleep(random(80, 121));
                }
            }
        }
        return areSettingsOpen();
    }

    /**
     * Closes clan Settings interface.
     *
     * @return <tt>true</tt> if closed/has been closed; otherwise <tt>false</tt>
     */
    public boolean closeSettings() {
        if (areSettingsOpen()) {
            if (methods.interfaces.getComponent(INTERFACE_CLAN_CHAT_SETTINGS, INTERFACE_CLAN_CHAT_SETTINGS_CLOSE_BUTTON).doClick())
                for (byte i = 0; i < 10 && areSettingsOpen(); i++) {
                    sleep(random(80, 121));
                }
        }
        return !areSettingsOpen();
    }

    /**
     * Checks to see if the Settings interface is open/valid.
     *
     * @return <tt>true</tt> if open; otherwise <tt>false</tt>
     */
    public boolean areSettingsOpen() {
        return methods.interfaces.get(INTERFACE_CLAN_CHAT_SETTINGS).isValid();
    }
}